//Basic Raycasting code for hitscan, line checks, etc
//Original code written by rdude, revised and optimized by Saxashitter and rdude, further revision by LJ, neither are affiliated with nor do they endorse rdude or this mod.
/*
local raycastMobj
addHook("NetVars", function(sync)
	raycastMobj = sync($)
end)

mobjinfo[freeslot "MT_GREENRAY"] = {
	spawnstate = S_THOK,
	radius = FU,
	height = FU,
	flags = MF_NOGRAVITY|MF_NOCLIPTHING
}

local function XYZCollide(x, y, z, mo)
	local flags = mo.flags
	if flags & (MF_NOCLIP|MF_NOCLIPTHING) then return false end
	if not (flags & MF_SHOOTABLE) then return false end
	local halfrad = mo.radius
	local pos = mo.x //we're gonna be snobby and reuse this var for both x, y, and z to try and really squeeze out all the optimization 
	if x > pos+(halfrad) then return false end
	if x < pos-(halfrad) then return false end
	local pos = mo.y
	if y > pos+(halfrad) then return false end
	if y < pos-(halfrad) then return false end
	local pos = mo.z
	if z > mo.height+pos then return false end
	if z < pos then return false end
	return true
end

local function ParseArg(args, variable, default)
	if not args then
		return default
	end

	if args[variable] == nil then
		return default
	end

	if default ~= nil
	and type(args[variable]) ~= type(default)then
		return default
	end

	return args[variable]
end

rawset(_G, "P_OldAngleRaycast", function(args)
	// Arguments
	local x = ParseArg(args, "x", 0)
	local y = ParseArg(args, "y", 0)
	local z = ParseArg(args, "z", 0)
	local ang = ParseArg(args, "ang", 0)
	local zang = ParseArg(args, "zang", 0)
	local distance = ParseArg(args, "distance", 240*FU)
	local steps = ParseArg(args, "steps", 32)
	local callback = ParseArg(args, "callback")
	local callback2 = ParseArg(args, "callback2")
	local arg = ParseArg(args, "arg")
	local sarg = ParseArg(args, "sarg")
	local larg = ParseArg(args, "larg")
	local tclip = ParseArg(args, "tclip")
	local lclip = ParseArg(args, "lclip")
	local ignore = ParseArg(args, "ignore")

	if not (raycastMobj and raycastMobj.valid) then
		raycastMobj = P_SpawnMobj(0,0,0, MT_GREENRAY)
	end

	local collisionlist = {}
	local collisionset = {}
	local vx = FixedMul(cos(ang), cos(zang))
	local vy = FixedMul(sin(ang), cos(zang))
	local vz = sin(zang)

	local move = distance/steps

	for stepcount = 1, steps do
		x = $ + FixedMul(move, vx)
		y = $ + FixedMul(move, vy)
		z = $ + FixedMul(move, vz)
		
		if callback then
			callback(x, y, z, arg)
		end
		
		if (raycastMobj and raycastMobj.valid) then
			P_SetOrigin(raycastMobj, x, y, z) //trouble area here, says the mobj doesnt exist
		end

		if searchBlockmap("objects", function(ref, object)
			if object == ignore then return nil end
			if collisionset[object] then return nil end
			if XYZCollide(x, y, z, object) then
				table.insert(collisionlist, {x, y, z, object})
				collisionset[object] = true
				if callback2 then
					callback2(x, y, z, sarg, object)
				end
				if tclip == true or tclip == 1 then return true
				else return nil end
			end
		end, raycastMobj) == false then break end
	
		if lclip == true or lclip == 1 then
			local sect = raycastMobj.subsector.sector
			if z < sect.floorheight or z > sect.ceilingheight then
				if not (sect.f_slope or sect.c_slope) then
					if callback2 then
						callback2(x-FixedMul(move, vx), y-FixedMul(move, vy), z-FixedMul(move, vz), larg or sarg)
					end
					break
				end
			end
			local shouldbreak = 0
			for fof in sect.ffloors() do
				if not (fof.flags & FOF_SOLID) then continue end
				if (z <= fof.topheight and z >= fof.bottomheight) then
					shouldbreak = 1
					break
				end
			end
			if shouldbreak == 1 then
				if callback2 then
					callback2(x-FixedMul(move, vx), y-FixedMul(move, vy), z-FixedMul(move, vz), larg or sarg)
				end
				break
			end
			if R_PointInSubsectorOrNil(x, y) == nil then
				if callback2 then
					callback2(x-FixedMul(move, vx), y-FixedMul(move, vy), z-FixedMul(move, vz), larg or sarg)
				end
				break
			end
		end
	end
	P_RemoveMobj(raycastMobj)
	return collisionlist
end)

COM_AddCommand("raytest", function(bruh, x, y, z, ang, zang, step, amount)
	P_AngleRaycast(tonumber(x)*FU, tonumber(y)*FU, tonumber(z)*FU, FixedAngle(tonumber(ang)*FU), FixedAngle(tonumber(zang)*FU), tonumber(step), tonumber(amount), P_SpawnMobj, nil, MT_THOK, nil, true, true)
end)